Skip to content

feat(security): make the resolved permission posture explicit and observable - #231

Merged
Zongwei9888 merged 3 commits into
HKUDS:mainfrom
raymondginger2018-sudo:security-posture
Sep 16, 2026
Merged

Zongwei9888 merged 3 commits into
HKUDS:mainfrom
raymondginger2018-sudo:security-posture

Conversation

@raymondginger2018-sudo

Copy link
Copy Markdown
Contributor

What

The effective permission posture is resolved from four interacting knobs — permission mode, access preset, command sandbox, approval policy — and no single one of them tells a reader whether a run was gated or wide open. An unattended full_auto run and an approval-gated one look identical in a transcript.

This makes the resolved posture explicit, visible, and tested:

  • core/harness/policy.pydescribe_security_posture(profile, *, sandbox_backend=None) returns a flat, string-friendly mapping (unattended being the headline fact) suitable for a log line or a structured event without further shaping. It reports facts; it does not judge them. Also states the module's public surface via __all__.
  • core/agent_setup.py — log the flattened posture once per session, next to the engine it describes, so "could a rewritten tool call have run unattended?" is answerable from the log instead of being reconstructed from four separate fields.
  • workflows/code_implementation_workflow.py — state default_mode=PermissionMode.FULL_AUTO at the call site: this workflow is the one caller that intentionally runs with no approver. No behaviour change; the intent is simply readable where it applies.
  • tests/test_harness_policy.py — 3 cases: the trap below, the gated modes, and rule counting.

The subtlety it encodes

Legacy full_auto short-circuits the engine with an unconditional ALLOW while still reporting an on_request approval policy. A report that trusted the policy field alone would therefore label the most permissive configuration as gated — the exact mistake this helper exists to prevent. That is why unattended is derived from both fields, and why the test asserts it.

Verification

  • pytest tests/test_harness_policy.py19 passed
  • pytest tests/test_harness_policy.py tests/application/test_agent_adapter.py tests/test_mcp_server.py tests/test_spawn_agent.py tests/test_subagent_composition.py75 passed
  • ruff check + ruff format --check on all four files with ruff 0.15.21 (the version pinned by .pre-commit-config.yaml) → clean
  • Pure addition: no behaviour change for existing callers.

The effective security posture is spread across four interacting knobs
(permission mode, access preset, command sandbox, approval policy), so no
single field in a transcript tells a reader whether the run was gated or wide
open: an unattended `full_auto` run and an attended one look identical.

`describe_security_posture(profile, *, sandbox_backend=None)` returns a flat,
string-friendly mapping suitable for a log line or a structured event, with
`unattended` as the headline fact. It reports facts; it does not judge them.

The one subtlety it encodes: legacy `full_auto` short-circuits the engine with
an unconditional ALLOW while still reporting `on_request`, so trusting the
approval policy field alone would label the most permissive configuration as
gated -- the exact mistake this helper exists to prevent.

Also exports the module's public names via `__all__` so the intended surface is
explicit. Pure addition; no behaviour change to existing callers.
`build_agent_session` resolves the security profile on every call, but the
result was invisible afterwards: the four knobs (permission mode, access
preset, command sandbox, approval policy) interact, so an unattended
`full_auto` run reads identically to an approval-gated one in a transcript.

Log the flattened posture once per session, next to the engine it describes,
so "could a rewritten tool call have run unattended?" is answerable from the
log rather than reconstructed from four separate fields.
This workflow is the one caller that intentionally runs with no approver.
Passing `default_mode=PermissionMode.FULL_AUTO` at the call site instead of
inheriting the signature default makes the intent readable where it applies,
and gives "who runs with no approver?" a grep-able answer. No behaviour change.
@Zongwei9888

Copy link
Copy Markdown
Collaborator

Merged into main as 65d9d1b. Thank you @raymondginger2018-sudodescribe_security_posture() is a small addition but it answers the one question a transcript could not ("was anybody going to be asked?"), and encoding the legacy full_auto short-circuit in the unattended derivation, with a test pinning it, is exactly the trap worth documenting.

@Zongwei9888
Zongwei9888 merged commit 65d9d1b into HKUDS:main Sep 16, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants